package com.gopay.bis.service.bank.impl;

import com.gopay.bis.manager.bank.BankOrderManager;
import com.gopay.bis.manager.bank.NuccSerialManager;
import com.gopay.bis.service.bank.BankIntrChannConfService;
import com.gopay.bis.service.bank.BankIntrChannConfService.OutStlmTranCode;
import com.gopay.bis.service.bank.BankOrderService;
import com.gopay.common.Result;
import com.gopay.common.cache.client.RedisClient;
import com.gopay.common.cipher.utils.LoggerMaskUtils;
import com.gopay.common.constants.bank.BankConstants;
import com.gopay.common.constants.bank.BankOrderStatus;
import com.gopay.common.constants.bank.BisBankBusinessProd;
import com.gopay.common.constants.bank.BisBankInterfaceChannel;
import com.gopay.common.constants.bank.NuccConstants;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.cps.manager.order.CpsGeneralMainOrderQueryManager;
import com.gopay.common.domain.bank.BankOrder;
import com.gopay.common.domain.bank.BcdlMessage;
import com.gopay.common.domain.bank.BcdlQueryBalance;
import com.gopay.common.domain.bank.BcdlResult;
import com.gopay.common.domain.bank.bcdl.BcdlPacket;
import com.gopay.common.domain.bank.bcdl.BcdlPacketRes;
import com.gopay.common.domain.bis.BaseBisBankConfig;
import com.gopay.common.domain.bis.BisBankBcdlOrder;
import com.gopay.common.domain.cps.CpsGenMainOrder;
import com.gopay.common.exception.GopayException;
import com.gopay.common.util.DateUtils;
import com.gopay.common.util.spring.SpringContextUtil;
import com.gopay.remote.bank.BcdlInteractRemoteService;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.StaleObjectStateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 银企直连银行操作Service实现
 * 
 * @BankBcdlServiceImpl.java
 * @author WangHongFei
 */
@Service("bankBcdlService")
public class BankBcdlServiceImpl implements BcdlInteractRemoteService {

    private static Logger logger = LoggerFactory
            .getLogger(BankBcdlServiceImpl.class);
    @Resource(name = "bankOrderService")
    private BankOrderService bankOrderService;
    @Resource(name = "bankIntrChannConfService")
    private BankIntrChannConfService bankIntrChannConfService;

    @Resource(name = "bankOrderManager")
    private BankOrderManager bankOrderManager;
    @Resource(name = "bisConfig")
    private Map<String, String> bisConfig;
    @Resource(name = "cpsGeneralMainOrderQueryManager")
    private CpsGeneralMainOrderQueryManager mainOrderQuery;
    @Resource(name = "nuccSerialManager")
    private NuccSerialManager nuccSerialManager;
    @Value("${NUCC.SERIAL.CONTROL}")
    private String nuccSerialControl;

    @Override
    public BcdlResult eft(BcdlMessage base) {
        logger.error("bcdl pay request: " + toLogString(base));
        
        BcdlResult r = new BcdlResult();
        r = checkParam(base);
        if(!r.isSuccess()&&StringUtils.equals(ProcCodeConstants.PROC_CODE_100E6027, r.getResultCode())){
            return r;
        }
        try {
            //base.setBankBusProd(BisBankBusinessProd._09);
            //base.setBankIntrChann(BisBankInterfaceChannel._00);
            //checkBankIntrChan(base);
            // 获取主订单表
            CpsGenMainOrder mainOrder = getMainOrder(base.getOrderId());
            if (BisBankInterfaceChannel._18.equals(base.getBankIntrChann())) {  
                // 如果缓存中没有流水号规则缓存则主动调用接口
                if (!RedisClient.exists(NuccConstants.NUCC_SERIAL_REDIS_KEY)) {
                    nuccSerialManager.getFlowIdRule();
                }
                // 主动调用接口后还是没有则报错
                if (!RedisClient.exists(NuccConstants.NUCC_SERIAL_REDIS_KEY)) {
                    // 抛出缓存中不存在流水号异常
                    throw new GopayException(ProcCodeConstants.PROC_CODE_100E6121);
                }
                // 从缓存中获取规则组装流水号
                Map<String, String> map = RedisClient.hgetAll(NuccConstants.NUCC_SERIAL_REDIS_KEY);
                String serial = map.get(NuccConstants.NUCC_SERIAL_REDIS_FIELD + new SecureRandom().nextInt(map.size()));
                // 交易流水号
                base.setBankOrderId(DateUtils.format(new Date(), "yyyyMMdd") + base.getOrderId() + nuccSerialControl
                        + serial);
            } else {
                base.setBankOrderId(base.getOrderId());
            }
            String gopayOrderId = base.getOrderId();
            BankOrder bankOrder = bankOrderService
                    .getBankOrderById(gopayOrderId);
            Result statusResult = getOrderStatus(bankOrder);
            logger.error(gopayOrderId + " procCode: "
                    + toLogString(statusResult));
            // 交易已成功：直接返回成功结果
            if (ProcCodeConstants.PROC_CODE_100S1000.equals(statusResult
                    .getResultCode())) {
                r.setSuccess(true);
                r.setResultCode(ProcCodeConstants.PROC_CODE_100S1000);
                logger.error("efs result: " + toLogString(r));
                return r;
            }
            // 交易状态不明确
            if (!ProcCodeConstants.PROC_CODE_100E6001.equals(statusResult
                    .getResultCode())) {
                r.setSuccess(true);
                r.setResultCode(ProcCodeConstants.PROC_CODE_100S1000);
            }
            // 不存在记录，新增bankorder记录直接发起银行交易
            BcdlInteractRemoteService bankService = getService(base);
//            base.setBankOrderId(gopayOrderId);
            BankOrder newBankOrder = bankOrderService.addBankOrder(base); // 保存订单
            r.setSuccess(true);
            r.setResultCode(ProcCodeConstants.PROC_CODE_100S1000);
            logger.error("efs outOrderId: " + base.getOutOrderId()
                    + ", orderId: " + gopayOrderId);
        } catch (GopayException e) {
            logger.error(base.getOutOrderId() + "BcdlInteractRemoteService eft error: ", e);
            r.setResultCode(e.getErrCode());
            r.setSuccess(false);
        } catch (Exception e) {
            logger.error(base.getOutOrderId() + "BcdlInteractRemoteService eft error: ", e);
            r.setResultCode(ProcCodeConstants.PROC_CODE_100F1002);
            r.setSuccess(false);
        }
        logger.error(base.getOutOrderId() + "efs result: " + toLogString(r));
        return r;
    }

    @Override
    public BcdlResult sendBank(BcdlMessage base) {
        logger.error("bcdl send bank request: " + LoggerMaskUtils.maskString(toLogString(base)));
        BcdlResult r = new BcdlResult();
        try {
            base.setBankBusProd(BisBankBusinessProd._09);
//            base.setBankIntrChann(BisBankInterfaceChannel._00);
            checkBankIntrChan(base);
            String gopayOrderId = base.getOrderId();
//            BankOrder bankOrder = bankOrderService
//                    .getBankOrderById(gopayOrderId);
            // 获取银行订单修改为按银行订单号查询 add by zhegnxue
            BankOrder bankOrder = bankOrderService.getBankOrderById(base.getOutOrderId());
            
            Result statusResult = getOrderStatus(bankOrder);
            logger.error(gopayOrderId + "send bank procCode: "
                    + toLogString(statusResult));
            // 发送银行前加orderStatus判断，已受理状态才发送
            if (!BankOrderStatus.ACCEPTED.equals(bankOrder.getOrderStatus())) {
                logger.error(gopayOrderId + "send bank orderstatus: "
                        + toLogString(statusResult));
                r.setResultCode(ProcCodeConstants.PROC_CODE_100E6066);
                r.setSuccess(false);
                return r;
            }
            
            // 直接发起银行交易
            BcdlInteractRemoteService bankService = getService(base);
            logger.error("send bank outOrderId: " + base.getOutOrderId()
                    + ", orderId: " + gopayOrderId);
            r.setResultCode(ProcCodeConstants.PROC_CODE_100E6066);
            bankResUpdateOrderBeforeBcdl(r, bankOrder);
            BcdlResult eftResult = bankService.eft(base);
            if (null == eftResult) {
                logger.error("send bank result is null, outOrderId："
                        + bankOrder.getOutOrderId());
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E6066);// 状态处理中
            }
            r = eftResult;
            bankResUpdateOrder(r, bankOrder);
        } catch (GopayException e) {
            logger.error(base.getOutOrderId() + "BcdlInteractRemoteService send bank error: ", e);
            r.setResultCode(e.getErrCode());
            r.setSuccess(false);
        } catch (Exception e) {
            logger.error(base.getOutOrderId() + "BcdlInteractRemoteService  send bank  error: ", e);
            r.setResultCode(ProcCodeConstants.PROC_CODE_100F1002);
            r.setSuccess(false);
        }
        logger.error(base.getOutOrderId() + " send bank  result: " + toLogString(r));
        return r;
    }

    @Override
    public BcdlResult query(BcdlMessage base) {
        logger.error("efs query request: " + toLogString(base));
        BcdlResult result = new BcdlResult();
        try {
            if (null == base || StringUtils.isBlank(base.getOutOrderId())) {
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E5096);
            }
            BcdlInteractRemoteService bankService = getService(base);
            result = bankService.query(base);
            if (null == result) {
                logger.error("efs query result is null, outOrderId："
                        + base.getOutOrderId());
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E6066);// 状态处理中
            }
            // 此处不更新BisBankOrder表，在efs中或者对账逻辑中更新
        } catch (GopayException e) {
            if (null != base) {
                logger.error(base.getOutOrderId() + "BcdlInteractRemoteService query error: ", e);
            } else {
                logger.error("base is null , BcdlInteractRemoteService query error: ", e);
            }
            if (null == result) {
                result = new BcdlResult();
            }
            result.setResultCode(e.getErrCode());
            result.setSuccess(false);
        } catch (Exception e) {
            logger.error(base.getOutOrderId() + "BcdlInteractRemoteService query error: ", e);
            result.setResultCode(ProcCodeConstants.PROC_CODE_100F1002);
            result.setSuccess(false);
        }
        logger.error(base.getOutOrderId() + "efs query result: " + toLogString(result));
        return result;
    }
    
    @Override
    public BcdlResult queryBalance(BcdlMessage base) {
        logger.error("bcdl queryBalance request: " + toLogString(base));
        
        BcdlResult r = new BcdlResult();
        try {
            // 若当前存在查询请求，则再不处理其他查询请求
            List<BcdlQueryBalance> bcdlQuerys = bankOrderService.getBcdlQueryByBankCodeAndOrderStatus(base.getBank(),
                    BankOrderStatus.ACCEPTED);
            if (bcdlQuerys != null && bcdlQuerys.size() > 0) {
                r.setSuccess(true);
                r.setResultCode(ProcCodeConstants.PROC_CODE_100S1000);
                logger.error(bcdlQuerys.get(0).getQueryOrderId() + " bcdl queryBalance is has query order: "
                        + toLogString(r));
                return r;
            }
            
            checkBankIntrChan(base);
            bankOrderService.addBcdlQueryOrder(base); // 保存订单
            r.setSuccess(true);
            r.setResultCode(ProcCodeConstants.PROC_CODE_100S1000);
            logger.error("bcdl queryBalance outOrderId: " + base.getOrderId());
        } catch (GopayException e) {
            logger.error("BcdlInteractRemoteService queryBalance error: ", e);
            r.setResultCode(e.getErrCode());
            r.setSuccess(false);
        } catch (Exception e) {
            logger.error("BcdlInteractRemoteService queryBalance error: ", e);
            r.setResultCode(ProcCodeConstants.PROC_CODE_100F1002);
            r.setSuccess(false);
        }
        logger.error(base.getOrderId() + "bcdl queryBalance result: " + toLogString(r));
        return r;
    }

    @Override
    public BcdlResult sendBankQueryBalance(BcdlMessage base) {
        logger.error("bcdl sendBankQueryBalance request: " + toLogString(base));
        BcdlResult result = new BcdlResult();
        try {
            if (null == base || StringUtils.isBlank(base.getOrderId())) {
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E5096);
            }
            BcdlQueryBalance bcdlquery = bankOrderService.getBcdlQueryById(base.getOrderId());
            BcdlInteractRemoteService bankService = getService(base);
            result = bankService.queryBalance(base);
            if (null == result) {
                logger.error("bcdl sendBankQueryBalance result is null, orderId：" + base.getOrderId());
                throw new GopayException(ProcCodeConstants.PROC_CODE_100F1002);
            }
            if(bcdlquery!=null){
            	bankResUpdateQueryOrder(result, bcdlquery);
            }
        } catch (GopayException e) {
            if (null != base ) {
                logger.error(base.getOrderId() + "BcdlInteractRemoteService sendBankQueryBalance error: ", e);
            } else {
                logger.error("base is null , BcdlInteractRemoteService sendBankQueryBalance error: ", e);
            }
            if (null == result) {
                result = new BcdlResult();
            }
            result.setResultCode(e.getErrCode());
            result.setSuccess(false);
        } catch (Exception e) {
            logger.error(base.getOrderId() + "BcdlInteractRemoteService sendBankQueryBalance error: ", e);
            result.setResultCode(ProcCodeConstants.PROC_CODE_100F1002);
            result.setSuccess(false);
        }
        logger.error(base.getOrderId() + "bcdl sendBankQueryBalance result: " + toLogString(result));
        return result;
    }
    
    @Override
    public BcdlResult sendBankPacket(BcdlPacket bcdlPacket) {
        logger.error("bcdlPacket send bank request: " + toLogString(bcdlPacket));
        List<BcdlMessage> bcdlList = bcdlPacket.getBcdlMessages(); // 批量发起订单list
        List<BcdlMessage> newBcdlList = new ArrayList<BcdlMessage>();
        BcdlResult result = new BcdlResult();
        try {
            checkBankIntrChan(bcdlPacket);
            if (null != bcdlList && bcdlList.size() > 0) {
                // 循环处理银企付款批量订单
                for (int i = 0; i < bcdlList.size(); i++) {
                    // 银企订单处理结果
                    BcdlMessage bcdlMessage = bcdlList.get(i);
                    String gopayOrderId = bcdlMessage.getOrderId();
                    BankOrder bankOrder = bankOrderService.getBankOrderById(gopayOrderId);
                    Result statusResult = getOrderStatus(bankOrder);
                    logger.error(gopayOrderId + "bcdlPacket send bank procCode: " + toLogString(statusResult));

                    // 发送银行前加orderStatus判断，已受理状态才发送
                    if (!BankOrderStatus.ACCEPTED.equals(bankOrder.getOrderStatus())) {
                        logger.error(gopayOrderId + "bcdlPacket send bank orderstatus: " + toLogString(statusResult));
                        continue;
                    }

                    logger.error("bcdlPacket send bank packetNo: " + bcdlPacket.getPacketNo() + ", orderId: "
                            + gopayOrderId);
                    result.setResultCode(ProcCodeConstants.PROC_CODE_100E6066);

                    boolean boo = bankResUpdateOrderBeforeBatchBcdl(result, bankOrder, bcdlPacket);
                    if (!boo) {
                    	logger.error(gopayOrderId + "bcdlPacket send bank Before error " );
                        continue;
                    }
                    newBcdlList.add(bcdlMessage);
                }
            }
            
            bcdlPacket.setBcdlMessages(newBcdlList);

            if (null ==  bcdlPacket.getBcdlMessages() ||  bcdlPacket.getBcdlMessages().size() <= 0) {
                logger.error("bcdlPacket is null, packetNo：" + bcdlPacket.getPacketNo());
                throw new GopayException(ProcCodeConstants.PROC_CODE_100F1002);
            }
            
            // 直接发起银行交易
            BcdlInteractRemoteService bankService = getService(bcdlPacket);
            result = bankService.sendBankPacket(bcdlPacket);
            if (null == result) {
                logger.error("bcdlPacket send bank result is null, packetNo：" + bcdlPacket.getPacketNo());
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E6066);// 状态处理中
            }
            // 循环更新银企付款批量订单状态
//            for (int i = 0; i < bcdlPacket.getBcdlMessages().size(); i++) {
//                BankOrder bankOrder = bankOrderService.getBankOrderById(bcdlPacket.getBcdlMessages().get(i)
//                        .getOrderId());
//                bankResUpdateOrder(result, bankOrder);
//            }
        } catch (GopayException e) {
            if (null != bcdlPacket) {
                logger.error(bcdlPacket.getPacketNo() + " BcdlInteractRemoteService bcdlPacket send bank error: ", e);
            } else {
                logger.error("bcdlPacket is null , BcdlInteractRemoteService bcdlPacket send bank error: ", e);
            }
            if (null == result) {
                result = new BcdlResult();
            }
            result.setResultCode(e.getErrCode());
            result.setSuccess(false);
        } catch (Exception e) {
            logger.error(bcdlPacket.getPacketNo() + " BcdlInteractRemoteService bcdlPacket send bank  error: ", e);
            result.setResultCode(ProcCodeConstants.PROC_CODE_100F1002);
            result.setSuccess(false);
        }
        logger.error(bcdlPacket.getPacketNo() + " bcdlPacket send bank  result: " + toLogString(result));
        return result;
    }

    @Override
    public BcdlPacketRes queryPacket(BcdlPacket bcdlPacket) {
        logger.error("bcdlPacket query request: " + toLogString(bcdlPacket));
        BcdlPacketRes result = new BcdlPacketRes();
        try {
            if (null == bcdlPacket || StringUtils.isBlank(bcdlPacket.getPacketNo())) {
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E5096);
            }
            BcdlInteractRemoteService bankService = getService(bcdlPacket);
            result = bankService.queryPacket(bcdlPacket);
            if (null == result) {
                logger.error("bcdlPacket query result is null, packetNo：" + bcdlPacket.getPacketNo());
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E6066);// 状态处理中
            }
            // 批量查询在此处更新银行订单表状态
            List<BcdlResult> resultList = result.getBcdlResults();
            if (null != resultList && resultList.size() > 0) {
                // 循环处理银企付款批量订单结果
                for (int i = 0; i < resultList.size(); i++) {
                    BcdlResult bcdlResult = resultList.get(i);
                    BankOrder bankOrder = bankOrderService.getBankOrderById(bcdlResult.getGopayOrderId());
                    bankOrder.setTotalCheckTimes(bankOrder.getTotalCheckTimes()+1);
                    //add by lilili 更新前判断订单状态为进行中才更新
                    if(bankOrder.getOrderStatus().equals(BankOrderStatus.PROCESS)){
                    	batchQryResUpdateOrder(bcdlResult, bankOrder);
                    }
                }
            }
        } catch (GopayException e) {
            if (null != bcdlPacket) {
                logger.error(bcdlPacket.getPacketNo() + " BcdlInteractRemoteService bcdlPacket query error: ", e);
            } else {
                logger.error("bcdlPacket is null , BcdlInteractRemoteService bcdlPacket query error: ", e);
            }
            if (null == result) {
                result = new BcdlPacketRes();
            }
            result.setResultCode(e.getErrCode());
            result.setSuccess(false);
        } catch (Exception e) {
            logger.error(bcdlPacket.getPacketNo() + " BcdlInteractRemoteService bcdlPacket query error: ", e);
            result.setResultCode(ProcCodeConstants.PROC_CODE_100F1002);
            result.setSuccess(false);
        }
        logger.error(bcdlPacket.getPacketNo() + " bcdlPacket query result: " + toLogString(result));
        return result;
    }

    @Override
    public BcdlResult queryAcctDetail(BcdlMessage base) {
        logger.error("bcdl queryAcctDetail request: " + toLogString(base));
        BcdlResult result = new BcdlResult();
        try {
            BcdlInteractRemoteService bankService = getService(base);
            result = bankService.queryAcctDetail(base);
            if (null == result) {
                logger.error("bcdl queryAcctDetail result is null, orderId：" + base.getOrderId());
                throw new GopayException(ProcCodeConstants.PROC_CODE_100F1002);
            }
        } catch (GopayException e) {
            logger.error(base.getOrderId() + "BcdlInteractRemoteService queryAcctDetail error: ", e);
            if (null == result) {
                result = new BcdlResult();
            }
            result.setResultCode(e.getErrCode());
            result.setSuccess(false);
        } catch (Exception e) {
            logger.error(base.getOrderId() + "BcdlInteractRemoteService queryAcctDetail error: ", e);
            result.setResultCode(ProcCodeConstants.PROC_CODE_100F1002);
            result.setSuccess(false);
        }
        logger.error(base.getOrderId() + "bcdl queryAcctDetail result: " + toLogString(result));
        return result;
    }

    /**
     * 银行相应更新订单
     * 
     * @param result
     * @param bankOrder
     */
    private void bankResUpdateOrder(BcdlResult result, BankOrder bankOrder) {
        String status;// 银行订单状态
        String bankOrderId=bankOrder.getOutOrderId();
        bankOrder = bankOrderService.getBankOrderById(bankOrderId);
        if(bankOrder==null){
        	logger.error("bankResUpdateOrder error,orderId:"+bankOrderId+" is null");
        	return;
        }
        if(!BankOrderStatus.PROCESS.equals(bankOrder.getOrderStatus())){
        	logger.error("bankResUpdateOrder error,orderId:"+bankOrder.getOrderId()+"订单状态为"+bankOrder.getOrderStatus());
//          status = BankOrderStatus.PROCESS;// 非明确成功或失败的都是进行中状态
        	return;
        }
        if (ProcCodeConstants.PROC_CODE_100S1000.equals(result.getResultCode())) {
            status = BankOrderStatus.BANK_CALL_SUCCESS;
            bankOrder.setTranFinishTime(new Date());
            bankOrder.setOrderStatus(status);
        } else if (ProcCodeConstants.PROC_CODE_100E6027.equals(result
                .getResultCode())) {
            status = BankOrderStatus.FAIL;
            bankOrder.setTranFinishTime(new Date());
            bankOrder.setOrderStatus(status);
        } else {
        	logger.error("bankResUpdateOrder error,orderId:"+bankOrder.getOrderId()+"result状态为"+result.getResultCode());
//          status = BankOrderStatus.PROCESS;// 非明确成功或失败的都是进行中状态
        	return;
        }
        
        bankOrder.setLastUpdTs(new Date());
        try {
            bankOrderService.updateBankOrder(bankOrder);
        } catch (Exception e) {
//            Date finishTime = bankOrder.getTranFinishTime();
//            bankOrder = bankOrderService.getBankOrderById(bankOrder
//                    .getOutOrderId());
//            bankOrder.setOrderStatus(status);
//            bankOrder.setLastUpdTs(new Date());
//            if (finishTime != null) {
//                bankOrder.setTranFinishTime(finishTime);
//            }
//            bankOrderService.updateBankOrder(bankOrder);
        	logger.error("bankResUpdateOrder error,orderId:"+bankOrder.getOrderId()+"result:"+result.getResultCode(),e);
        }
    }
    
    /**
     * 银企批量查询返回更新订单
     * 
     * @param result
     * @param bankOrder
     */
    private void batchQryResUpdateOrder(BcdlResult result, BankOrder bankOrder) {
        String status;// 银行订单状态
        //bankOrder = bankOrderService.getBankOrderById(bankOrder.getOrderId());
        if (ProcCodeConstants.PROC_CODE_100S1000.equals(result.getResultCode())) {
            status = BankOrderStatus.AUTO_CHECK_SUCCESS;
            bankOrder.setTranFinishTime(new Date());
        } else if (ProcCodeConstants.PROC_CODE_100E6027.equals(result
                .getResultCode())) {
            status = BankOrderStatus.FAIL;
            bankOrder.setTranFinishTime(new Date());
        } else {
            status = BankOrderStatus.PROCESS;// 非明确成功或失败的都是进行中状态
        }
        bankOrder.setOrderStatus(status);
        bankOrder.setLastUpdTs(new Date());
        try {
            bankOrderService.updateBankOrder(bankOrder);
        } catch (StaleObjectStateException e) {
            Date finishTime = bankOrder.getTranFinishTime();
            bankOrder = bankOrderService.getBankOrderById(bankOrder
                    .getOrderId());
            bankOrder.setOrderStatus(status);
            bankOrder.setLastUpdTs(new Date());
            if (finishTime != null) {
                bankOrder.setTranFinishTime(finishTime);
            }
            bankOrderService.updateBankOrder(bankOrder);
        }
    }
    
    /**
     * 银企直连发起更新订单,并记录发起时间
     * 
     * @param result
     * @param bankOrder
     */
    @Transactional
    public void bankResUpdateOrderBeforeBcdl(BcdlResult result, BankOrder bankOrder) throws GopayException {
        try {
            logger.error("插入发往银行日志--开始,gopayOrderId="+bankOrder.getOrderId());
            bankOrderManager.saveBcdlSendBankLog(bankOrder);//插入发往银行日志 by zhoutong 20171012
            logger.error("插入发往银行日志--结束,gopayOrderId="+bankOrder.getOrderId());

            String status = BankOrderStatus.PROCESS;// 非明确成功或失败的都是进行中状态
            bankOrder = bankOrderService.getBankOrderById(bankOrder.getOutOrderId());
            bankOrder.setOrderStatus(status);
            bankOrder.setLastUpdTs(new Date());
            bankOrder.setSendBankTm(new Date());
            bankOrderService.updateBankOrder(bankOrder);
        } catch (Exception e) {
            logger.error("BCDL发往银行前更新数据库异常,gopayOrderId="+bankOrder.getOrderId(), e);
            throw new GopayException(ProcCodeConstants.PROC_CODE_100F1002);
            //bankOrder = bankOrderService.getBankOrderById(bankOrder
            //        .getOrderId());
            //bankOrder.setOrderStatus(status);
            //bankOrder.setLastUpdTs(new Date());
            //bankOrder.setSendBankTm(new Date());
            //bankOrderService.updateBankOrder(bankOrder);
        }
    }

    /**
     * 批量银企直连发起更新订单,并记录发起时间
     *
     * @param result
     * @param bankOrder
     * @param bcdlPacket
     */
    @Transactional
    public boolean bankResUpdateOrderBeforeBatchBcdl(BcdlResult result, BankOrder bankOrder, BcdlPacket bcdlPacket) throws GopayException {
        try {
            logger.error("插入发往银行日志--开始,gopayOrderId="+bankOrder.getOrderId());
            bankOrderManager.saveBcdlSendBankLog(bankOrder);//插入发往银行日志 by zhoutong 20171012
            logger.error("插入发往银行日志--结束,gopayOrderId="+bankOrder.getOrderId());

            String status = BankOrderStatus.PROCESS;// 非明确成功或失败的都是进行中状态
            bankOrder = bankOrderService.getBankOrderById(bankOrder.getOrderId());
            bankOrder.setOrderStatus(status);
            bankOrder.setLastUpdTs(new Date());
            bankOrder.setSendBankTm(new Date());
            bankOrderService.updateBankOrder(bankOrder);

            // 更新批量包号
            BisBankBcdlOrder bcdlOrder = bankOrderService.getBankBcdlOrderById(bankOrder.getOrderId());
            bcdlOrder.setPacketNo(bcdlPacket.getPacketNo());
            bankOrderService.updateBankBcdlOrder(bcdlOrder);

            return true;
        } catch (Exception e) {
            logger.error("BCDL批量发往银行前更新数据库异常,gopayOrderId="+bankOrder.getOrderId(), e);
            return false;
        }
    }

    /**
     * 更新银企直联查询订单状态
     * 
     * @param result
     * @param bcdlquery
     */
    private void bankResUpdateQueryOrder(BcdlResult result, BcdlQueryBalance bcdlquery) {
        String status;// 银行订单状态
        bcdlquery = bankOrderService.getBcdlQueryById(bcdlquery.getQueryOrderId());
        if (ProcCodeConstants.PROC_CODE_100S1000.equals(result.getResultCode())) {
            status = BankOrderStatus.BANK_CALL_SUCCESS;
            bcdlquery.setBankAccNum((String) result.getModel("payAccNum"));
            bcdlquery.setQueryBalance((String) result.getModel("balance"));
            bcdlquery.setQueryBankReturnTime(new Date());
        } else {
            status = BankOrderStatus.FAIL;
        }
        bcdlquery.setQueryOrderStatus(status);
        bcdlquery.setQueryLastTime(new Date());
        try {
            bankOrderService.updateBcdlQueryOrder(bcdlquery);
        } catch (StaleObjectStateException e) {
            bcdlquery = bankOrderService.getBcdlQueryById(bcdlquery.getQueryOrderId());
            bcdlquery.setQueryOrderStatus(status);
            bcdlquery.setQueryLastTime(new Date());
            bcdlquery.setBankAccNum((String) result.getModel("payAccNum"));
            bcdlquery.setQueryBalance((String) result.getModel("balance"));
            bcdlquery.setQueryBankReturnTime(new Date());
            bankOrderService.updateBcdlQueryOrder(bcdlquery);
        }
    }

    /**
     * 校验银企直连银行通道信息
     * 
     * @param base
     * @throws GopayException
     */
    private void checkBankIntrChan(BcdlMessage base) throws GopayException {
        String bank = base.getBank();
        if (StringUtils.isBlank(bank)) {
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E7003);
        }
        BaseBisBankConfig config = bankIntrChannConfService
                .findBcdlIntrConfig(bank);
        bankIntrChannConfService.checkBankIntrChan(config,
                OutStlmTranCode._1001);
        base.setBankIntrChannConf(config);
    }
    
    /**
     * 校验银企直连批量银行通道信息
     * 
     * @param bcdlPacket
     * @throws GopayException
     */
    private void checkBankIntrChan(BcdlPacket bcdlPacket) throws GopayException {
        String bank = bcdlPacket.getBank();
        if (StringUtils.isBlank(bank)) {
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E7003);
        }
        BaseBisBankConfig config = bankIntrChannConfService
                .findBcdlIntrConfig(bank);
        bankIntrChannConfService.checkBankIntrChan(config,
                OutStlmTranCode._1001);
//        bcdlPacket.setBankIntrChannConf(config);
    }

    /**
     * 获取银企直连service
     * 
     * @param base
     * @return BcdlInteractRemoteService
     * @throws GopayException
     */
    private BcdlInteractRemoteService getService(BcdlMessage base)
            throws GopayException {
        // 获取SPRING加载的BeanName
        String beanName = getBeanName(base.getBank());
        if (base.getBankIntrChann() != null
                && (BisBankInterfaceChannel._18.value.equals(base.getBankIntrChann().value))) {
            // 网联渠道
            beanName = "NUCCPAY-BCDL";
        }
        // 装配各银行个性化信息参数
        if (false == SpringContextUtil.containsBean(beanName)) {
            logger.error("spring bean does not exist: " + beanName);
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6044,
                    "not support bcdl: " + base.getBank());
        }
        BcdlInteractRemoteService bankService = (BcdlInteractRemoteService) SpringContextUtil
                .getBean(beanName);
        return bankService;
    }
    
    /**
     * 获取银企直连批量service
     * 
     * @param bcdlPacket
     * @return BcdlInteractRemoteService
     * @throws GopayException
     */
    private BcdlInteractRemoteService getService(BcdlPacket bcdlPacket)
            throws GopayException {
        // 获取SPRING加载的BeanName
        String beanName = getBeanName(bcdlPacket.getBank());
        // 装配各银行个性化信息参数
        if (false == SpringContextUtil.containsBean(beanName)) {
            logger.error("spring bean does not exist: " + beanName);
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6044,
                    "not support bcdl: " + bcdlPacket.getBank());
        }
        BcdlInteractRemoteService bankService = (BcdlInteractRemoteService) SpringContextUtil
                .getBean(beanName);
        return bankService;
    }

    /**
     * 转账前置处理
     * 
     * @param base
     * @param oldBankOrder
     * @return BcdlResult
     * @throws GopayException
     */
    private BcdlResult dealQueryResult(BcdlMessage base, BankOrder oldBankOrder)
            throws GopayException {
        base.setOutOrderId(oldBankOrder.getOutOrderId());
        BcdlResult queryR = this.query(base);
        bankResUpdateOrder(queryR, oldBankOrder);
        return queryR;
    }

    /**
     * 获取银企直连service
     * 
     * @param bankOrder
     * @return BcdlInteractRemoteService
     * @throws GopayException
     */
    private Result getOrderStatus(BankOrder bankOrder) {
        Result r = new Result();
        r.setSuccess(true);
        if (null == bankOrder) {
            r.setResultCode(ProcCodeConstants.PROC_CODE_100E6001);
            return r;// 不存在记录
        }
        if (BankOrderStatus.PROCESS.equals(bankOrder.getOrderStatus())) {
            r.setResultCode(ProcCodeConstants.PROC_CODE_100E6066);
            r.setDefaultModel(bankOrder);
            return r;// 处理中
        }
        if (BankOrderStatus.BANK_CALL_SUCCESS
                .equals(bankOrder.getOrderStatus())
                || BankOrderStatus.AUTO_CHECK_SUCCESS.equals(bankOrder
                        .getOrderStatus())
                || BankOrderStatus.CHECK_SUCCESS.equals(bankOrder
                        .getOrderStatus())) {
            r.setResultCode(ProcCodeConstants.PROC_CODE_100S1000);
            r.setDefaultModel(bankOrder);
            return r;// 成功
        }
        r.setResultCode(ProcCodeConstants.PROC_CODE_100E6027);
        return r;// 失败
    }
    private BcdlResult checkParam(BcdlMessage base){
        BcdlResult result = new BcdlResult();
        if(StringUtils.isBlank(base.getRecvBankProvNo())){
            result.setSuccess(false);
            result.setResultCode(ProcCodeConstants.PROC_CODE_100E6027);
            result.setErrorMsg("收款方省代码不能为空");
        }
        if(StringUtils.isBlank(base.getRecvBankAcctNum())){
            result.setSuccess(false);
            result.setResultCode(ProcCodeConstants.PROC_CODE_100E6027);
            result.setErrorMsg("收款方账号不能为空");
        }
        if(StringUtils.isBlank(base.getRecvBankAcctName())){
            result.setSuccess(false);
            result.setResultCode(ProcCodeConstants.PROC_CODE_100E6027);
            result.setErrorMsg("收款方姓名不能为空");
        }
        return result;
    }
    /**
     * BeanName规范:银行编码-交易类型，如TBANK-BCDL
     * 
     * @param bankCode
     *            银行编码
     * @return String
     * @throws GopayException
     */
    private String getBeanName(String bankCode) throws GopayException {
        String beanSuffix = "-BCDL";
        if (StringUtils.equals(bankCode, BankConstants.BANK_LOGO_SDB)) {
            bankCode = BankConstants.BANK_LOGO_PAB;
        }
        String beanName = bankCode + beanSuffix;
        return beanName;
    }

    /**
     * 日志输出类型转换
     * 
     * @param log
     * @return String
     */
    private String toLogString(Object log) {
        return LoggerMaskUtils.maskString(ToStringBuilder.reflectionToString(log,
                ToStringStyle.DEFAULT_STYLE));
    }

    @Override
    public BcdlResult eftRetry(BcdlMessage base) {
		logger.error("bcdl eftRetry unreachable request: " + toLogString(base));
		// 重发功能不用，暂时关闭 update by lilili
		return null;
//        BcdlResult r = new BcdlResult();
//        try {
//            
//            String gopayOrderId = base.getOrderId();
//            BankOrder bankOrder = bankOrderService
//                    .getBankOrderById(gopayOrderId);
//            logger.error("eftRetry before bankOrder: " + toLogString(bankOrder));
////          // 只处理进行中的订单
//            if(!BankOrderStatus.PROCESS.equals(bankOrder.getOrderStatus())){
//                r.setSuccess(true);
//                r.setResultCode(ProcCodeConstants.PROC_CODE_100E5042);
//                logger.error(base.getOrderId() + "eftRetry result: " + toLogString(r));
//                return r;
//            }
//            base.setBank(bankOrder.getBankCode());
//            base.setBankBusProd(BisBankBusinessProd._09);
//            base.setBankIntrChann(BisBankInterfaceChannel._00);
//            checkBankIntrChan(base);
//            
//            bankOrderService.addBankOrderDealLog(bankOrder);
//            
//            //如果存在发往银行日志记录，先删除，防止违反唯一约束    add by lilili   2017/08/11
//            BcdlSendBankLog bcdlSendBankLog = bankOrderService.getBcdlSendLogById(gopayOrderId);
//            if(bcdlSendBankLog != null){
//            	bankOrderService.deleteBcdlSendLog(bcdlSendBankLog);
//            }
//            
//            //回溯状态，从新发起
//            bankOrder.setOrderStatus(BankOrderStatus.ACCEPTED);
//            bankOrder.setTotalCheckTimes(1);
//            bankOrder.setLastUpdTs(new Date());
//            bankOrder.setRemark3("retry"+DateUtils.getCurrDate());
//            bankOrderService.updateBankOrder(bankOrder);
//            
//            // 更新重发状态
//            BisBankBcdlOrder bcdlOrder = bankOrderService.getBankBcdlOrderById(gopayOrderId);
//            bcdlOrder.setReonlinepay(1);
//            bankOrderService.updateBankBcdlOrder(bcdlOrder);
//            r.setSuccess(true);
//            r.setResultCode(ProcCodeConstants.PROC_CODE_100S1000);
//            logger.error("eftRetry after bankOrder: " + toLogString(bankOrder));
//        } catch (GopayException e) {
//            logger.error(base.getOrderId() + "BcdlInteractRemoteService eftRetry error: ", e);
//            r.setResultCode(e.getErrCode());
//            r.setSuccess(false);
//        } catch (Exception e) {
//            logger.error(base.getOrderId() + "BcdlInteractRemoteService eftRetry error: ", e);
//            r.setResultCode(ProcCodeConstants.PROC_CODE_100F1002);
//            r.setSuccess(false);
//        }
//        logger.error(base.getOrderId() + "eftRetry result: " + toLogString(r));
//        return r;
    }
    
    /**
     * 获取订单信息
     * @param orderId
     * @return CpsGenMainOrder
     * @throws GopayException
     */
    private CpsGenMainOrder getMainOrder(String orderId) throws GopayException {
        if (orderId == null || "".equals(orderId)) {
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E5041);
        }
        // 获取主订单表
        CpsGenMainOrder mainOrder = mainOrderQuery.get(orderId);
        if (mainOrder == null) {
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E5041);
        }
        return mainOrder;
    }
}
